package com.gt.wxpay.cashier.common.runable;

import com.alibaba.fastjson.JSONObject;
import com.gt.wxpay.cashier.common.LocalTimeUtils;
import com.gt.wxpay.cashier.domain.dto.QueryRefundDto;
import com.gt.wxpay.cashier.domain.model.CashierPayment;
import com.gt.wxpay.cashier.domain.model.PaymentStatusEnum;
import com.gt.wxpay.cashier.domain.model.RefundStatusEnum;
import com.gt.wxpay.cashier.domain.model.TransactionTypeEnum;
import com.gt.wxpay.cashier.notifyRecord.application.NotifyRecordService;
import com.gt.wxpay.cashier.payment.application.PaymentService;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import com.wechat.pay.java.service.refund.model.Status;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;
import java.util.Objects;

/**
 * packageName com.gt.wxpay.cashier.common
 *
 * @author GuoTong
 * @version JDK 8
 * @className NotifyThreadRunnable
 * @date 2024/3/18
 * @description 通知线程处理
 */
@Slf4j
public class NotifyThreadRunnable implements Runnable {

    // 交易结果
    private Transaction transaction;

    // 支付订单记录
    private PaymentService paymentService;

    // 支付回调的日志记录
    private NotifyRecordService notifyRecordService;

    // 退款回调---
    private RefundNotification refundNotification;

    public NotifyThreadRunnable(Transaction transaction, PaymentService paymentService, NotifyRecordService notifyRecordService) {
        this.paymentService = paymentService;
        this.transaction = transaction;
        this.notifyRecordService = notifyRecordService;
    }

    public NotifyThreadRunnable(RefundNotification refundNotification, PaymentService paymentService, NotifyRecordService notifyRecordService) {
        this.paymentService = paymentService;
        this.refundNotification = refundNotification;
        this.notifyRecordService = notifyRecordService;
    }

    @Override
    public void run() {
        // 区分是下单支付回调|或者是退款成功回调
        if (this.transaction != null) {
            executePayOrderCallBackFunction();
        } else {
            executeRefundOrderCallBackFunction();
        }
    }

    /**
     * 退款成功回调
     */
    private void executeRefundOrderCallBackFunction() {
        Status refundStatus = refundNotification.getRefundStatus();
        // 获取商户的状态
        String outRefundNo = refundNotification.getOutRefundNo();
        // 更新退款状态
        CashierPayment cashierPayment = paymentService.queryByPamentNo(outRefundNo, TransactionTypeEnum.REFUND.code());
        // 做幂等====防止二刷
        if (Objects.equals(cashierPayment.getStatus(), RefundStatusEnum.SUCCESS.getCode())) {
            log.error("[退款回调] 重复的回调通知----->忽略");
            return;
        }
        cashierPayment.setChannelRefundStatus(refundStatus.name());
        String name = refundStatus.name();
        switch (name) {
            case "SUCCESS":
                cashierPayment.setStatus(RefundStatusEnum.SUCCESS.getCode());
                break;
            case "CLOSED":
                cashierPayment.setStatus(RefundStatusEnum.CLOSED.getCode());
                break;
            case "ABNORMAL":
                cashierPayment.setStatus(RefundStatusEnum.ABNORMAL.getCode());
                break;
        }
        paymentService.updateById(cashierPayment);
        // 触发退款成功事件
        QueryRefundDto body = buildQueryRefundDto(cashierPayment);
        boolean thatWasRequestOk = notifyRecordService.sendSuccessRefundCallBackMsg(cashierPayment.getNotifyUrl(), body);
        // 如果推送失败----就采取收银台会每隔6分钟通知一次，总共通知10次。
        if (!thatWasRequestOk) {
            log.info("Refund:===>>>>FAIL=====>>>通知失败，开始重试" + cashierPayment.getNotifyUrl());
            try {
                int count = 10;
                for (int i = 0; i < count; i++) {
                    // 当前线程睡眠6分钟
                    Thread.sleep(360000);
                    boolean tempResp = notifyRecordService.sendSuccessRefundCallBackMsg(cashierPayment.getNotifyUrl(), body);
                    if (tempResp) {
                        break;
                    }
                    log.info("Refund:===>>>>FAIL=====>>>第" + (i + 1) + "次通知失败");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 构建消息推送业务侧body
     *
     * @return QueryRefundDto
     */
    private QueryRefundDto buildQueryRefundDto(CashierPayment cashierPayment) {
        QueryRefundDto queryRefundDto = new QueryRefundDto();
        queryRefundDto.setRefundNo(refundNotification.getOutRefundNo());
        queryRefundDto.setRefundTime(LocalTimeUtils.dealFormatWithWx(refundNotification.getSuccessTime()));
        if (StringUtils.isNotBlank(refundNotification.getCreateTime())) {
            queryRefundDto.setCreateTime(LocalTimeUtils.dealFormatWithWx(refundNotification.getCreateTime()));
        } else {
            queryRefundDto.setCreateTime(cashierPayment.getChannelRefundCreateTime());
        }
        queryRefundDto.setRefundAmount(refundNotification.getAmount().getRefund());
        queryRefundDto.setAmount(refundNotification.getAmount().getTotal());
        switch (refundNotification.getRefundStatus().name()) {
            case "SUCCESS":
                queryRefundDto.setStatus(1);
                break;
            case "CLOSED":
                queryRefundDto.setStatus(2);
                break;
            case "ABNORMAL":
                queryRefundDto.setStatus(4);
                break;
            default:
                queryRefundDto.setStatus(3);
                break;
        }
        return queryRefundDto;
    }

    /**
     * 下单支付回调
     */
    private void executePayOrderCallBackFunction() {
        // 获取收银台的订单信息
        CashierPayment cashierPayment = paymentService.queryByPamentNo(transaction.getOutTradeNo());
        // 做幂等====防止二刷
        if (Objects.equals(cashierPayment.getStatus(), PaymentStatusEnum.PAYED.code())) {
            log.error("[支付回调] 重复的回调通知----->忽略");
            return;
        }
        // 从结果通知中获取信息并触发支付成功事件
        if (transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
            // 支付成功---就发布事件---NotifyUrl--回调业务侧的接口
            try {
                boolean thatWasRequestOk = sendMqSuccessPayCallBackMsg(cashierPayment.getNotifyUrl(), transaction);
                // 如果推送失败----就采取收银台会每隔6分钟通知一次，总共通知10次。
                if (!thatWasRequestOk) {
                    log.info("Transaction:===>>>>FAIL=====>>>通知失败，开始重试" + cashierPayment.getNotifyUrl());
                    int count = 10;
                    for (int i = 0; i < count; i++) {
                        // 当前线程睡眠6分钟
                        Thread.sleep(360000);
                        boolean tempResp = sendMqSuccessPayCallBackMsg(cashierPayment.getNotifyUrl(), transaction);
                        if (tempResp) {
                            break;
                        }
                        log.info("Transaction:===>>>>FAIL=====>>>第" + (i + 1) + "次通知失败");
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 更新数据库订单状态
            cashierPayment.setStatus(PaymentStatusEnum.PAYED.code());
        } else {
            log.info("Transaction:===>>>>FAIL=====>>>更新数据库订单状态");
            cashierPayment.setStatus(PaymentStatusEnum.PAYERROR.code());
        }
        String successTime = transaction.getSuccessTime();
        if (StringUtils.isNotBlank(successTime)) {
            Date successDate = LocalTimeUtils.dealDateFormatWithWx(successTime);
            cashierPayment.setSuccessTime(successDate);
        }
        // 交易金额
        cashierPayment.setSuccessAmount(transaction.getAmount().getTotal().longValue());
        cashierPayment.setCurrencyType(transaction.getAmount().getCurrency());
        // 取微信返回的流水号
        cashierPayment.setChannelFlowNo(transaction.getTransactionId());
        // 更新支付渠道返回的流水号--由预下单流水号转化为支付流水号
        cashierPayment.setChannelReturnCode(transaction.getTradeState().name());
        cashierPayment.setChannelReturnMessage(transaction.getTradeStateDesc());
        // 更新订单详情
        paymentService.updateById(cashierPayment);
    }

    /**
     * 当收银台收到第三方支付系统的订单支付结果通知后，会立即调用业务系统在订单创建时提供的支付结果通知url。
     *
     * @param notifyUrl
     */
    public boolean sendMqSuccessPayCallBackMsg(String notifyUrl, Transaction transaction) {
        // 订单支付结果通知
        JSONObject jsonData = new JSONObject();
        jsonData.put("notifyTime", new Date());
        jsonData.put("paymentNo", transaction.getOutTradeNo());
        jsonData.put("amount", transaction.getAmount().getTotal());
        Transaction.TradeStateEnum tradeState = transaction.getTradeState();
        switch (tradeState) {
            case SUCCESS:
                // 设置已支付
                jsonData.put("payStatus", PaymentStatusEnum.PAYED.code());
                break;
            case REFUND:
                jsonData.put("payStatus", PaymentStatusEnum.REFUNDING.code());
                break;
            case NOTPAY:
                jsonData.put("payStatus", PaymentStatusEnum.UNPAY.code());
                break;
            case CLOSED:
                jsonData.put("payStatus", PaymentStatusEnum.CLOSED.code());
                break;
            case REVOKED:
                jsonData.put("payStatus", PaymentStatusEnum.CANCELLED.code());
                break;
            case USERPAYING:
                jsonData.put("payStatus", PaymentStatusEnum.PAYING.code());
                break;
            case PAYERROR:
                jsonData.put("payStatus", PaymentStatusEnum.PAYERROR.code());
                break;
            default:
                break;
        }
        jsonData.put("payStatusDesc", transaction.getTradeStateDesc());
        jsonData.put("paySuccessTime", LocalTimeUtils.dealDateFormatWithWx(transaction.getSuccessTime()));
        return notifyRecordService.sendMqSuccessPayCallBackMsg(notifyUrl, jsonData);
    }

}
